package pe.com.rimac.portal.facturacion.controlador.consulta;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletRequest;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.portlet.bind.annotation.ActionMapping;
import org.springframework.web.portlet.bind.annotation.RenderMapping;
import org.springframework.web.portlet.bind.annotation.ResourceMapping;

import pe.com.rimac.portal.common.exception.ServiceException;
import pe.com.rimac.portal.facturacion.constantes.Constantes.Accion;
import pe.com.rimac.portal.facturacion.constantes.Constantes.ContentType;
import pe.com.rimac.portal.facturacion.constantes.Constantes.Error;
import pe.com.rimac.portal.facturacion.constantes.Constantes.ParametroRequest;
import pe.com.rimac.portal.facturacion.constantes.Constantes.Preferencia;
import pe.com.rimac.portal.facturacion.constantes.Constantes.Reporte;
import pe.com.rimac.portal.facturacion.constantes.Constantes.Vista;
import pe.com.rimac.portal.facturacion.handler.ListHandler;
import pe.com.rimac.portal.facturacion.handler.ListHandlerFactory;
import pe.com.rimac.portal.facturacion.handler.SearchCriteria;
import pe.com.rimac.portal.facturacion.modelo.Factura;
import pe.com.rimac.portal.facturacion.servicio.AseguradoService;
import pe.com.rimac.portal.facturacion.util.CredentialUtil;
import pe.com.rimac.portal.facturacion.util.PumaUtil;
import pe.com.rimac.portal.facturacion.util.PumaUtil.PumaAttribute;
import pe.com.rimac.portal.facturacion.util.SessionHelper;
import pe.com.rimac.portal.service.facturacion.criterio.CriterioBusqueda;
import pe.com.rimac.portal.service.paperless.model.TipoRetorno;

/**
 * Clase encargada de manejar todos los eventos realizados en la pantalla de Consulta de Documentos Electr&eacute;nicos.
 * 
 * @author Andres Deza Villacorta - Synopsis S.A
 * 
 */
@Controller(value = "consultaController")
@RequestMapping("VIEW")
public class ConsultaController
{
	private static final Logger logger = Logger.getLogger(ConsultaController.class);
	@Autowired
	private CredentialUtil credentialUtil;
	@Autowired
	private PumaUtil pumaUtil;
	@Autowired
	private AseguradoService aseguradoService;
	@Autowired
	private ListHandlerFactory listHandlerFactory;

	/**
	 * Muestra el formulario de b&uacute;squeda de documentos electr&oacute;nicos.
	 * 
	 * @param request
	 * @param response
	 * @param modelo
	 * @return
	 */
	@RenderMapping
	public String mostrarFormularioBusqueda(RenderRequest request, RenderResponse response, Model modelo)
	{
		addToModel(request, modelo);
		return Vista.VISTA_CONSULTA_DOCUMENTOS;
	}

	/**
	 * Muestra el formulario de b&uacute;squeda de documentos electr&oacute;nicos con los resultados obtenidos de la
	 * b&uacute;squeda realizada.
	 * 
	 * @param request
	 * @param response
	 * @param modelo
	 * @return
	 */
	@RenderMapping(params = ParametroRequest.PARAMETRO_ACCION + "=" + Accion.ACCION_BUSCAR)
	public String mostrarResultadosBusqueda(RenderRequest request, RenderResponse response, Model modelo)
	{
		addToModel(request, modelo);
		return getView(request);
	}

	/**
	 * Muestra la tabla de resultados obtenidos de la b&uacute;squeda de documentos realizada.
	 * 
	 * @param request
	 * @param response
	 * @param modelo
	 * @return
	 */
	@RenderMapping(params = ParametroRequest.PARAMETRO_ACCION + "=" + Accion.ACCION_MOSTRAR_TABLA_RESULTADOS)
	public String mostrarTablaResultados(RenderRequest request, RenderResponse response, Model modelo)
	{
		addToModel(request, modelo);
		return Vista.VISTA_CONSULTA_DOCUMENTOS_RESULTADOS;
	}

	/**
	 * M&eacute;todo encargado de realizar la b&uacute;squeda de facturas electr&oacute;nicas.
	 * 
	 * @param request
	 * @param response
	 */
	@ActionMapping(params = ParametroRequest.PARAMETRO_ACCION + "=" + Accion.ACCION_BUSCAR)
	public void search(ActionRequest request, ActionResponse response)
	{
		logger.info("buscar method");
		SessionHelper.clearSession(request);
		ListHandler listHandler = listHandlerFactory.getFacturasListHandler();
		listHandler.setPageSize(Integer.parseInt(request.getPreferences().getValue(Preferencia.PAGE_SIZE, "10")));
		listHandler.setSearchCriteria(getSearchCriteria(request));
		try
		{
			listHandler.executeSearch();
			if (listHandler.getPagesCount() > 0)
			{
				SessionHelper.setListHandler(request, listHandler);
				SessionHelper.setInitIndex(request, 0);
			}
			else
			{
				response.setRenderParameter(ParametroRequest.SIN_RESULTADOS, "true");
			}
		}
		catch (ServiceException e)
		{
			logger.error("Ocurrio un error al consultar el servicio de documentos.", e);
			response.setRenderParameter(ParametroRequest.ES_ERROR, "true");
			response.setRenderParameter(ParametroRequest.CODIGO_ERROR, Error.CODIGO_ERROR_CONSULTA_DOCUMENTOS);
		}
		SessionHelper.setView(request, Vista.VISTA_CONSULTA_DOCUMENTOS);
		response.setRenderParameter(ParametroRequest.PARAMETRO_ACCION, Accion.ACCION_BUSCAR);
	}

	/**
	 * Exporta la factura electr&oacute;nica al formato seleccionado. PDF o XML.
	 * 
	 * @param request
	 * @param response
	 */
	@ResourceMapping(value = Accion.ACCION_EXPORTAR)
	public void exportarFactura(ResourceRequest request, ResourceResponse response)
	{
		logger.info("exportarFactura method");
		ListHandler listHandler = SessionHelper.getListHandler(request);
		Factura facturaSeleccionada = listHandler.getSelected(request.getParameter(ParametroRequest.NUMERO_FACTURA));
		String formato = request.getParameter(ParametroRequest.FORMATO_EXPORT);
		String filename = facturaSeleccionada.getSerie() + "-" + facturaSeleccionada.getDocumento();
		try
		{
			if (Reporte.EXTENSION_PDF.equals(formato))
			{
				String url = aseguradoService.obtenerURLFacturaDigital(facturaSeleccionada, TipoRetorno.URL_PDF,
						credentialUtil.getPrincipal(), credentialUtil.getCredentials());
				obtenerFacturaDigital(filename, url, ContentType.PDF, response);
			}
			else if (Reporte.EXTENSION_XML.equals(formato))
			{
				String url = aseguradoService.obtenerURLFacturaDigital(facturaSeleccionada, TipoRetorno.URL_XML,
						credentialUtil.getPrincipal(), credentialUtil.getCredentials());
				obtenerFacturaDigital(filename, url, ContentType.XML, response);
			}
		}
		catch (ServiceException e)
		{
			logger.error("Ocurrio un error al consultar el servicio de documentos.", e);
		}
		catch (FileNotFoundException e)
		{
			logger.error("Ocurrio un error al descargar la factura electronica.", e);
		}
	}

	/**
	 * M&eacute;todo encargado de mostrar la lista de facturas de la primera p&aacute;gina.
	 * 
	 * @param request
	 * @param response
	 */
	@ActionMapping(params = ParametroRequest.PARAMETRO_ACCION + "=" + Accion.ACCION_GO_TO_FIRST_PAGE)
	public void goToFirstPage(ActionRequest request, ActionResponse response)
	{
		logger.info("goToFirstPage method");
		ListHandler listHandler = SessionHelper.getListHandler(request);
		listHandler.getFirstPage();
		SessionHelper.setInitIndex(request, 0);
		response.setRenderParameter(ParametroRequest.PARAMETRO_ACCION, Accion.ACCION_MOSTRAR_TABLA_RESULTADOS);
	}

	/**
	 * M&eacute;todo encargado de mostrar la lista de facturas de la &uacute;ltima p&aacute;gina.
	 * 
	 * @param request
	 * @param response
	 */
	@ActionMapping(params = ParametroRequest.PARAMETRO_ACCION + "=" + Accion.ACCION_GO_TO_LAST_PAGE)
	public void goToLastPage(ActionRequest request, ActionResponse response)
	{
		logger.info("goToLastPage method");
		ListHandler listHandler = SessionHelper.getListHandler(request);
		listHandler.getLastPage();
		SessionHelper.setInitIndex(request, listHandler.getPagesCount() - 3);
		response.setRenderParameter(ParametroRequest.PARAMETRO_ACCION, Accion.ACCION_MOSTRAR_TABLA_RESULTADOS);
	}

	/**
	 * M&eacute;todo encargado de mostrar la lista de facturas de la p&aacute;gina previa a la que se est&aacute;
	 * mostrando.
	 * 
	 * @param request
	 * @param response
	 */
	@ActionMapping(params = ParametroRequest.PARAMETRO_ACCION + "=" + Accion.ACCION_GO_TO_PREVIOUS_PAGE)
	public void goToPreviousPage(ActionRequest request, ActionResponse response)
	{
		logger.info("goToPreviousPage method");
		ListHandler listHandler = SessionHelper.getListHandler(request);
		listHandler.getPreviousPage();
		int initIndex = SessionHelper.getInitIndex(request);
		if (initIndex > 0)
		{
			initIndex -= 1;
		}
		SessionHelper.setInitIndex(request, initIndex);
		response.setRenderParameter(ParametroRequest.PARAMETRO_ACCION, Accion.ACCION_MOSTRAR_TABLA_RESULTADOS);
	}

	/**
	 * M&eacute;todo encargado de mostrar la lista de facturas de la p&aacute;gina siguiente a la que se est&aacute;
	 * mostrando.
	 * 
	 * @param request
	 * @param response
	 */
	@ActionMapping(params = ParametroRequest.PARAMETRO_ACCION + "=" + Accion.ACCION_GO_TO_NEXT_PAGE)
	public void goToNextPage(ActionRequest request, ActionResponse response)
	{
		logger.info("goToNextPage method");
		ListHandler listHandler = SessionHelper.getListHandler(request);
		listHandler.getNextPage();
		int initIndex = SessionHelper.getInitIndex(request);
		if (initIndex + 3 < listHandler.getPagesCount())
		{
			initIndex += 1;
		}
		SessionHelper.setInitIndex(request, initIndex);
		response.setRenderParameter(ParametroRequest.PARAMETRO_ACCION, Accion.ACCION_MOSTRAR_TABLA_RESULTADOS);
	}

	/**
	 * M&eacute;todo encargado de mostrar la lista de facturas de la p&aacute;gina seleccionada.
	 * 
	 * @param request
	 * @param response
	 */
	@ActionMapping(params = ParametroRequest.PARAMETRO_ACCION + "=" + Accion.ACCION_GET_PAGE)
	public void getPage(ActionRequest request, ActionResponse response)
	{
		logger.info("getPage method");
		int page = Integer.parseInt(request.getParameter(ParametroRequest.PAGINA));
		ListHandler listHandler = SessionHelper.getListHandler(request);
		listHandler.getPage(page);
		response.setRenderParameter(ParametroRequest.PARAMETRO_ACCION, Accion.ACCION_MOSTRAR_TABLA_RESULTADOS);
	}

	/**
	 * M&eacute;todo encargado de marcar la factura seleccionada en pantalla.
	 * 
	 * @param request
	 * @param response
	 */
	@ActionMapping(params = ParametroRequest.PARAMETRO_ACCION + "=" + Accion.ACCION_MARCAR)
	public void mark(ActionRequest request, ActionResponse response)
	{
		logger.info("mark method");
		String numeroFactura = request.getParameter(ParametroRequest.NUMERO_FACTURA);
		ListHandler listHandler = SessionHelper.getListHandler(request);
		listHandler.mark(numeroFactura);
		response.setRenderParameter(ParametroRequest.PARAMETRO_ACCION, Accion.ACCION_MOSTRAR_TABLA_RESULTADOS);
	}

	/**
	 * M&eacute;todo encargado de marcar todas las facturas mostradas en pantalla.
	 * 
	 * @param request
	 * @param response
	 */
	@ActionMapping(params = ParametroRequest.PARAMETRO_ACCION + "=" + Accion.ACCION_MARCAR_TODO)
	public void markAll(ActionRequest request, ActionResponse response)
	{
		logger.info("markAll method");
		ListHandler listHandler = SessionHelper.getListHandler(request);
		listHandler.markAll();
		response.setRenderParameter(ParametroRequest.PARAMETRO_ACCION, Accion.ACCION_MOSTRAR_TABLA_RESULTADOS);
	}

	/**
	 * M&eacute;todo encargado de desmarcar todas las facturas mostradas en pantalla.
	 * 
	 * @param request
	 * @param response
	 */
	@ActionMapping(params = ParametroRequest.PARAMETRO_ACCION + "=" + Accion.ACCION_DESMARCAR_TODO)
	public void unmarkAll(ActionRequest request, ActionResponse response)
	{
		logger.info("unmarkAll method");
		ListHandler listHandler = SessionHelper.getListHandler(request);
		listHandler.unmarkAll();
		response.setRenderParameter(ParametroRequest.PARAMETRO_ACCION, Accion.ACCION_MOSTRAR_TABLA_RESULTADOS);
	}

	/**
	 * Obtiene los valores en pantalla y los almacena en el objeto SearchCriteria a ser utilizado para realizar la
	 * b&uacute;squeda de facturas electr&oacute;nicos.
	 * 
	 * @param request
	 * @return
	 */
	private SearchCriteria getSearchCriteria(ActionRequest request)
	{
		logger.info("getSearchCriteria method");
		SearchCriteria searchCriteria = new SearchCriteria();
		searchCriteria.setCriterioBusqueda(CriterioBusqueda.fromValue(request
				.getParameterValues(ParametroRequest.TIPO_BUSQUEDA)[0]));
		searchCriteria.setTipoDocumentoCliente(pumaUtil.getAttributeValue(PumaAttribute.DOCUMENT_NUMBER));
		searchCriteria.setNumeroDocumentoCliente(request.getRemoteUser());
		searchCriteria.setCodigoEmpresa(request.getParameter(ParametroRequest.EMPRESA));
		searchCriteria.setFechaInicio(request.getParameter(ParametroRequest.FECHA_INICIO));
		searchCriteria.setFechaFin(request.getParameter(ParametroRequest.FECHA_FIN));
		searchCriteria.setTipoDocumentoSUNAT(request.getParameter(ParametroRequest.TIPO_DOCUMENTO_SUNAT));
		searchCriteria.setSerieDocumentoSUNAT(request.getParameter(ParametroRequest.SERIE_DOCUMENTO_SUNAT));
		searchCriteria.setNumeroDocumentoSUNAT(request.getParameter(ParametroRequest.NUMERO_DOCUMENTO_SUNAT));
		searchCriteria.setProductoFechaInicio(request.getParameter(ParametroRequest.PRODUCTO_FECHA_INICIO));
		searchCriteria.setProductoFechaFin(request.getParameter(ParametroRequest.PRODUCTO_FECHA_FIN));
		searchCriteria.setProducto(request.getParameter(ParametroRequest.PRODUCTO));
		searchCriteria.setPoliza(request.getParameter(ParametroRequest.POLIZA));
		searchCriteria.setDocumentoCobro(request.getParameter(ParametroRequest.DOCUMENTO_COBRO));
		return searchCriteria;
	}

	/**
	 * M&eacute;todo encargado de agregar los objetos necesarios para mostrar los elementos en las vistas.
	 * 
	 * @param request
	 * @param modelo
	 */
	private void addToModel(PortletRequest request, Model modelo)
	{
		ListHandler listHandler = SessionHelper.getListHandler(request);
		if (listHandler != null)
		{
			modelo.addAttribute(ParametroRequest.HABILITAR_EXPORT, Boolean.valueOf(listHandler.getMarked().size() > 0));
			modelo.addAttribute(ParametroRequest.FACTURAS, listHandler.getCurrentPage());
			modelo.addAttribute(ParametroRequest.CANTIDAD_PAGINAS, String.valueOf(listHandler.getPagesCount()));
			modelo.addAttribute(ParametroRequest.PAGINA_ACTUAL, String.valueOf(listHandler.getCurrentIndex()));
			modelo.addAttribute(ParametroRequest.INDICE_INICIAL, String.valueOf(SessionHelper.getInitIndex(request)));
			modelo.addAttribute(ParametroRequest.TOTAL, String.valueOf(listHandler.getListSize()));
		}
		if (StringUtils.isNotEmpty(request.getParameter(ParametroRequest.ES_ERROR)))
		{
			modelo.addAttribute(ParametroRequest.ES_ERROR,
					Boolean.valueOf(request.getParameter(ParametroRequest.ES_ERROR)));
			modelo.addAttribute(ParametroRequest.CODIGO_ERROR, request.getParameter(ParametroRequest.CODIGO_ERROR));
		}
		if (StringUtils.isNotEmpty(request.getParameter(ParametroRequest.SIN_RESULTADOS)))
		{
			modelo.addAttribute(ParametroRequest.SIN_RESULTADOS,
					Boolean.valueOf(request.getParameter(ParametroRequest.SIN_RESULTADOS)));
		}
	}

	/**
	 * M&eacute;todo encargado de la selecci&oacute;n de la vista a ser mostrada al usuario.
	 * 
	 * @param request
	 * @return
	 */
	private String getView(RenderRequest request)
	{
		String view = SessionHelper.getView(request);
		if (view != null)
		{
			return view;
		}
		return Vista.VISTA_CONSULTA_DOCUMENTOS;
	}

	/**
	 * Obtiene la factura digital desde la URL dada por el servicio Paperless.
	 * 
	 * @param filename
	 * @param fileURL
	 * @param contentType
	 * @param response
	 * @throws FileNotFoundException
	 */
	private void obtenerFacturaDigital(String filename, String fileURL, String contentType, ResourceResponse response)
			throws FileNotFoundException
	{
		logger.info("obtenerFacturaDigital method");
		try
		{
			URL url = new URL(fileURL);
			URLConnection urlConn = url.openConnection();
			InputStream is = urlConn.getInputStream();
			response.setContentType(contentType);
			response.addProperty("Content-Disposition", "attachment; filename=\"" + filename + "\"");
			OutputStream outstream = response.getPortletOutputStream();
			int read = 0;
			byte[] bytes = new byte[1024];
			while ((read = is.read(bytes)) != -1)
			{
				outstream.write(bytes, 0, read);
			}
			is.close();
			outstream.flush();
			outstream.close();
			response.flushBuffer();
		}
		catch (MalformedURLException e)
		{
			e.printStackTrace();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}